{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "5d30e3f5",
   "metadata": {},
   "source": [
    "# Тестовое задание \"Открытый код\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e389c242",
   "metadata": {},
   "source": [
    "## Исходные данные:"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3574b725",
   "metadata": {},
   "source": [
    "Даны два числа N и m \n",
    "\n",
    "500 < N <= 1000\n",
    "\n",
    "10 < m <= 50"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "37ede837",
   "metadata": {},
   "source": [
    "## Программа 1 (формирование исходных данных):"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cfd6fa6f",
   "metadata": {},
   "source": [
    "По переданным числам N и m заполнить текстовый файл vectors.csv, состоящий из N строк, в каждой из которых m случайных чисел с плавающей точкой, каждое в диапазоне от -1 до +1, разделённых запятыми."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1cceac07",
   "metadata": {},
   "source": [
    "## Программа 2 (основное задание):"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c9c17607",
   "metadata": {},
   "source": [
    "На вход подаётся файл vectors.csv, созданный Программой 1. Каждая строка файла рассматривается как m-мерный вектор. Таким образом, получаем N векторов. Требуется вычислить евклидово расстояние между всеми парами различных векторов этого списка, и найти минимальное и максимальное расстояния, а также распределение расстояний."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "782dc2ea",
   "metadata": {},
   "source": [
    "### Дополнительное требование по использованию памяти:"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7bfc5dfc",
   "metadata": {},
   "source": [
    "Недопустимо создавать структуры данных размером более N * m элементов (больше, чем размер входного списка векторов)."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c594df06",
   "metadata": {},
   "source": [
    "### *Результат выводится в виде:*"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "102cff98",
   "metadata": {},
   "source": [
    "- номера векторов пары с минимальным расстоянием, и значение этого расстояния;\n",
    "- номера векторов пары с максимальным расстоянием, и значение этого расстояние;\n",
    "- изображение гистограммы распределения расстояний с шагом 0,1."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c28e164b",
   "metadata": {},
   "source": [
    "# Выполнение задания:"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a6f981ab",
   "metadata": {},
   "source": [
    "В задании не указано откуда будут передаваться числа, поэтому принимается, что их будет вводить пользователь по запросу программы. Также необходимо провести проверку переданных данных на соответствие требованиям, потому что пользователь может ввести их неправильно."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3f08571c",
   "metadata": {},
   "source": [
    "## *Запрос данных о значениях N и проверка полученных значений*:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "92d8d62b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Введите число N (или введите 'exit' для выхода): 893\n",
      "Введенное число 893 удовлетворяет условиям.\n"
     ]
    }
   ],
   "source": [
    "while True:\n",
    "    user_input = input(\"Введите число N (или введите 'exit' для выхода): \")\n",
    "\n",
    "    if user_input.lower() == 'exit':\n",
    "        print(\"Программа завершена.\")\n",
    "        break\n",
    "\n",
    "    try:\n",
    "        n = int(user_input)\n",
    "\n",
    "        if 500 < n <= 1000:\n",
    "            print(f\"Введенное число {n} удовлетворяет условиям.\")\n",
    "            break\n",
    "        elif n <= 500:\n",
    "            print(\"Число должно быть больше 500. Повторите ввод.\")\n",
    "        elif n > 1000:\n",
    "            print(\"Число должно быть равно или меньше 1000. Повторите ввод.\")\n",
    "    except ValueError:\n",
    "        print(\"Введите число цифрами, а не текстом. Повторите ввод.\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e1877a16",
   "metadata": {},
   "source": [
    "## *Запрос данных о значениях m и проверка полученных значений:*"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "adf3f511",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Введите число m (или введите 'exit' для выхода): 38\n",
      "Введенное число 38 удовлетворяет условиям.\n"
     ]
    }
   ],
   "source": [
    "while True:\n",
    "    user_input = input(\"Введите число m (или введите 'exit' для выхода): \")\n",
    "\n",
    "    if user_input.lower() == 'exit':\n",
    "        print(\"Программа завершена.\")\n",
    "        break\n",
    "\n",
    "    try:\n",
    "        m = int(user_input)\n",
    "\n",
    "        if 10 < m <= 50:\n",
    "            print(f\"Введенное число {m} удовлетворяет условиям.\")\n",
    "            break\n",
    "        elif m <= 10:\n",
    "            print(\"Число должно быть больше 10. Повторите ввод.\")\n",
    "        elif m > 50:\n",
    "            print(\"Число должно быть равно или меньше 50. Повторите ввод.\")\n",
    "    except ValueError:\n",
    "        print(\"Введите число цифрами, а не текстом. Повторите ввод.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7fa8f9e5",
   "metadata": {},
   "source": [
    "## *Формирование файла vectors.csv*:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "72d3b378",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Файл vectors.csv успешно создан с 893 строками, каждая длиной 38.\n"
     ]
    }
   ],
   "source": [
    "import random\n",
    "import csv\n",
    "\n",
    "def generate_vector(m):\n",
    "    return [round(random.uniform(-1, 1), 2) for _ in range(m)]\n",
    "\n",
    "def write_vectors_to_csv(filename, n, m):\n",
    "    with open(filename, 'w', newline='') as csvfile:\n",
    "        writer = csv.writer(csvfile)\n",
    "        \n",
    "        for _ in range(n):\n",
    "            vector = generate_vector(m)\n",
    "            writer.writerow(vector)\n",
    "\n",
    "if __name__ == \"__main__\":\n",
    "\n",
    "    filename = \"vectors.csv\"\n",
    "\n",
    "    write_vectors_to_csv(filename, n, m)\n",
    "    print(f\"Файл {filename} успешно создан с {n} строками, каждая длиной {m}.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "db77f7dd",
   "metadata": {},
   "source": [
    "## *Основное задание*:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "68da3b9d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Минимальное расстояние: Вектор 56 и Вектор 819, Значение: 2.863808652825813\n",
      "Максимальное расстояние: Вектор 94 и Вектор 737, Значение: 7.375913502746626\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAk0AAAHFCAYAAADv8c1wAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8pXeV/AAAACXBIWXMAAA9hAAAPYQGoP6dpAABPjElEQVR4nO3df3zN9f//8fsx29mPttN+2K+vbRSGhkIxKiTzayMqlbdFobzJjzfe/fx83q3eohL94E0qkZB+UeJtIRIfFGrlx8g7P85kM2PGZrbZXt8/+jifzja8zOZs3K6Xy+ty6Txfj/N6PV5n2L3X6/l6HYthGIYAAABwQbVc3QAAAEBNQGgCAAAwgdAEAABgAqEJAADABEITAACACYQmAAAAEwhNAAAAJhCaAAAATCA0AQAAmEBowjVh7ty5slgsjsXT01OhoaHq1KmTJk2apMzMzDLvSUpKksViuaT9nD59WklJSfr2228v6X3l7atevXqKj4+/pO1czMKFC/XGG2+Uu85isSgpKalS91fZvvnmG7Vu3Vo+Pj6yWCz64osvyq07cOCA08+79FKVx1l6+99++60sFoupPxODBg1SvXr1qqy3ytCxY0fH51irVi35+vqqQYMGuv/++/XZZ5+ppKSkzHvq1aunQYMGXdJ+Nm7cqKSkJJ04caJyGgcqQW1XNwBcSXPmzFHjxo1VVFSkzMxMbdiwQa+88opee+01ffzxx7r77rsdtUOGDFG3bt0uafunT5/WCy+8IOmPXy5mVWRfFbFw4ULt2LFDY8aMKbNu06ZNqlu3bpX3UFGGYahfv35q1KiRli5dKh8fH0VHR1/wPSNHjlT//v3LjF/J42zZsqU2bdqkpk2bXrF9VrUbbrhBCxYskCTl5eVp//79+uKLL3T//ffrjjvu0FdffSWbzeaoX7Jkifz8/C5pHxs3btQLL7ygQYMG6frrr6/M9oEKIzThmhITE6PWrVs7Xt97773629/+pttvv119+/bV3r17FRISIumPX6xV/cv19OnT8vb2viL7upi2bdu6dP8Xc/jwYR0/flx9+vRR586dTb0nMjLS5cfl5+fn8h4qm5eXV5ljGjJkiObMmaNHH31Ujz32mD7++GPHultuueVKtwhUCS7P4ZoXGRmpKVOm6NSpU5o1a5ZjvLxLZmvWrFHHjh0VGBgoLy8vRUZG6t5779Xp06d14MAB1alTR5L0wgsvOC5hnLsscW57P/74o+677z75+/vrxhtvPO++zlmyZImaN28uT09P3XDDDXrrrbec1p+79HjgwAGn8dKXhTp27Kjly5fr4MGDTpeqzinvstWOHTvUu3dv+fv7y9PTUzfffLM++OCDcvfz0Ucf6bnnnlN4eLj8/Px09913a8+ePef/4P9kw4YN6ty5s3x9feXt7a127dpp+fLljvVJSUmOUPnUU0/JYrFU2mWs81066tixY5mzhSdOnNC4ceN0ww03yGq1Kjg4WD169NDu3bvPu/3zXZ6bO3euoqOjZbVa1aRJE82bN6/c9xcWFmrChAlq3LixrFar6tSpo0ceeURHjx51qvv4448VFxensLAweXl5qUmTJnr66aeVl5fnVDdo0CBdd911+s9//qMePXrouuuuU0REhMaNG6eCgoLzf1AmPPLII+rRo4c+/fRTHTx40DFe+jMuKSnRhAkTFB0dLS8vL11//fVq3ry53nzzTUl//Lz//ve/S5Lq16/v+LN67jOsimMtKCjQiy++qCZNmsjT01OBgYHq1KmTNm7c6KgxDEMzZszQzTffLC8vL/n7++u+++7Tvn37nLb1008/KT4+XsHBwbJarQoPD1fPnj116NChy/p84XqcaQIk9ejRQ25ubvruu+/OW3PgwAH17NlTd9xxh95//31df/31+v3335WcnKzCwkKFhYUpOTlZ3bp10+DBgzVkyBBJcgSpc/r27asHH3xQw4YNK/OPfGkpKSkaM2aMkpKSFBoaqgULFmj06NEqLCzU+PHjL+kYZ8yYoccee0y//fablixZctH6PXv2qF27dgoODtZbb72lwMBAzZ8/X4MGDdKRI0f05JNPOtU/++yzat++vd577z2dPHlSTz31lBISEpSamio3N7fz7mfdunXq0qWLmjdvrtmzZ8tqtWrGjBlKSEjQRx99pAceeEBDhgxRixYt1LdvX8clN6vVetFjKCkp0dmzZ8uM16596f/0nTp1SrfffrsOHDigp556Sm3atFFubq6+++47paenq3Hjxqa3NXfuXD3yyCPq3bu3pkyZopycHCUlJamgoEC1av3f/8uWlJSod+/eWr9+vZ588km1a9dOBw8e1PPPP6+OHTtq69at8vLykiTt3btXPXr00JgxY+Tj46Pdu3frlVde0Q8//KA1a9Y47b+oqEi9evXS4MGDNW7cOH333Xf65z//KZvNpn/84x+X/Nn8Wa9evfTvf/9b69evV1RUVLk1r776qpKSkvRf//VfuvPOO1VUVKTdu3c75i8NGTJEx48f17Rp07R48WKFhYVJkuMSZ2Uf69mzZ9W9e3etX79eY8aM0V133aWzZ89q8+bNstvtateunSTp8ccf19y5czVq1Ci98sorOn78uF588UW1a9dOP//8s0JCQpSXl6cuXbqofv36+te//qWQkBBlZGRo7dq1OnXq1GV9tqgGDOAaMGfOHEOSsWXLlvPWhISEGE2aNHG8fv75540//xX57LPPDElGSkrKebdx9OhRQ5Lx/PPPl1l3bnv/+Mc/zrvuz6KiogyLxVJmf126dDH8/PyMvLw8p2Pbv3+/U93atWsNScbatWsdYz179jSioqLK7b103w8++KBhtVoNu93uVNe9e3fD29vbOHHihNN+evTo4VT3ySefGJKMTZs2lbu/c9q2bWsEBwcbp06dcoydPXvWiImJMerWrWuUlJQYhmEY+/fvNyQZkydPvuD2/lx7vmX9+vWO2qioKGPgwIFlttGhQwejQ4cOjtcvvviiIclYtWrVBfdd+nMs/XMoLi42wsPDjZYtWzqOzTAM48CBA4a7u7vTz+ejjz4yJBmff/650z62bNliSDJmzJhRbg8lJSVGUVGRsW7dOkOS8fPPPzvWDRw40JBkfPLJJ07v6dGjhxEdHX3BYzOMPz6Xm2666bzrV6xYYUgyXnnlFcdY6c84Pj7euPnmmy+4n8mTJ5f757q0yjjWefPmGZKMd99997z72bRpkyHJmDJlitN4Wlqa4eXlZTz55JOGYRjG1q1bDUnGF198ccG+UTNxeQ74X4ZhXHD9zTffLA8PDz322GP64IMPypySN+vee+81XXvTTTepRYsWTmP9+/fXyZMn9eOPP1Zo/2atWbNGnTt3VkREhNP4oEGDdPr0aW3atMlpvFevXk6vmzdvLklOl2lKy8vL0/fff6/77rtP1113nWPczc1NiYmJOnTokOlLfOUZPXq0tmzZUma5+eabL3lbK1asUKNGjZxuFqiIPXv26PDhw+rfv7/T5dGoqCjHGY1zli1bpuuvv14JCQk6e/asY7n55psVGhrqdMlv37596t+/v0JDQ+Xm5iZ3d3d16NBBkpSamuq0XYvFooSEBKex5s2bX/BnZdbF/h5J0m233aaff/5Zw4cP19dff62TJ09e0j4q+1hXrFghT09PPfroo+fd57Jly2SxWDRgwACnn0VoaKhatGjh+Fk0aNBA/v7+euqpp/T2229r165dl3RsqN64PAfoj1/ex44dU7Nmzc5bc+ONN2r16tV69dVXNWLECOXl5emGG27QqFGjNHr0aNP7OnepwYzQ0NDzjh07dsz0diri2LFj5fYaHh5e7v4DAwOdXp+7fJafn3/efWRnZ8swjEvaz6WoW7eu08T/y3H06FFFRkZe9nbOHc/5frZ/npt25MgRnThxQh4eHuVuKysrS5KUm5urO+64Q56enpowYYIaNWokb29vpaWlqW/fvmV+Bt7e3vL09HQas1qtOnPmzOUcmqT/C8nnfn7leeaZZ+Tj46P58+fr7bfflpubm+6880698sorF/15VcWxHj16VOHh4U6XRks7cuSIDMNw3ChS2g033CBJstlsWrdunV566SU9++yzys7OVlhYmIYOHar/+q//kru7+wWPD9UboQmQtHz5chUXF1/0MQF33HGH7rjjDhUXF2vr1q2aNm2axowZo5CQED344IOm9nUpz37KyMg479i5kHLuF0Lpia3nfqFWVGBgoNLT08uMHz58WJIUFBR0WduXJH9/f9WqVavK93Mhnp6e5U6AzsrKctp3nTp1KmUi77mf24V+tucEBQUpMDBQycnJ5W7L19dX0h9nBQ8fPqxvv/3WccZFkkuecbR06VJZLBbdeeed562pXbu2xo4dq7Fjx+rEiRNavXq1nn32WXXt2lVpaWny9vY+73ur4ljr1KmjDRs2qKSk5LzBKSgoSBaLRevXry93Pt2fx5o1a6ZFixbJMAz98ssvmjt3rl588UV5eXnp6aefrnCfcD0uz+GaZ7fbNX78eNlsNj3++OOm3uPm5qY2bdroX//6lyQ5LpWZObtyKXbu3Kmff/7ZaWzhwoXy9fVVy5YtJclxF9kvv/ziVLd06dIy27NaraZ769y5s+MX1J/NmzdP3t7elXIbvY+Pj9q0aaPFixc79VVSUqL58+erbt26atSo0WXv50Lq1atX5rP79ddfy1wW7N69u3799dcyE40vVXR0tMLCwvTRRx85Xco6ePCg051akhQfH69jx46puLhYrVu3LrOce07VuSBe+pf5n+8GvRLmzJmjFStW6KGHHjJ9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H6dx6f/ONJVed62NV8eeOOay46X/bJeczpEMo8zfhaKjB5T789flhqkL/Z3ysHpq/ofzyvxudNW/F6GhoQoNDS2318tx7ve2YZT/OTgYMAzDMH7//XdDkrFx40an8QkTJhjR0dHlvuf555839MefNBYWFhYWFpYavqSlpV0wK3Cm6X8FBQXJzc2tzNmczMzMMgn7nGeeeUZjx451vC4pKdHx48cVGBgoi8VSab2dPHlSERERSktLk5+fX6VttzrjmDnmqxXHzDFfrWryMRuGoVOnTik8PPyCdYSm/+Xh4aFWrVpp1apV6tOnj2N81apV6t27d7nvsVqtZa4DX3/99VXWo5+fX437g3i5OOZrA8d8beCYrw019ZhtNttFawhNfzJ27FglJiaqdevWio2N1TvvvCO73a5hw4a5ujUAAOBihKY/eeCBB3Ts2DG9+OKLSk9PV0xMjP79738rKirK1a0BAAAXIzSVMnz4cA0fPtzVbTixWq16/vnnz3tL6NWIY742cMzXBo752nAtHLPFMC52fx0AAABquboBAACAmoDQBAAAYAKhCQAAwARCEwAAgAmEphpgxowZql+/vjw9PdWqVSutX7/e1S1Vme+++04JCQkKDw+XxWLRF1984eqWqtykSZN06623ytfXV8HBwbrnnnu0Z88eV7dVpWbOnKnmzZs7HoIXGxurFStWuLqtK2bSpEmyWCwaM2aMq1upMklJSbJYLE5LVXxnWHXz+++/a8CAAQoMDJS3t7duvvlmbdu2zdVtVZl69eqV+TlbLBaNGDHC1a1VCUJTNffxxx9rzJgxeu655/TTTz/pjjvuUPfu3WW3213dWpXIy8tTixYtNH36dFe3csWsW7dOI0aM0ObNm7Vq1SqdPXtWcXFxysvLc3VrVaZu3bp6+eWXtXXrVm3dulV33XWXevfurZ07d7q6tSq3ZcsWvfPOO2revLmrW6lyN910k9LT0x3L9u3bXd1SlcrOzlb79u3l7u6uFStWaNeuXZoyZUqVflOEq23ZssXpZ7xq1SpJ0v333+/izqpI5XzdLarKbbfdZgwbNsxprHHjxsbTTz/too6uHEnGkiVLXN3GFZeZmWlIMtatW+fqVq4of39/47333nN1G1Xq1KlTRsOGDY1Vq1YZHTp0MEaPHu3qlqrM888/b7Ro0cLVbVxRTz31lHH77be7ug2X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mzd3/LfFYlFoaKgyMzMlSSkpKbrlllsUEBBQ7j62bdumLVu2OJ1ZKi4u1pkzZ3T69Gl5e3ubPnYAVYfQBOCqk5qaqvr165cZb9mypfbv368VK1Zo9erV6tevn+6++2599tln593W3//+d3399dd67bXX1KBBA3l5eem+++5TYWGhU527u7vTa4vF4rj85uXldcF+S0pK9MILL6hv375l1nl6el7wvQCuHEITgKvKmjVrtH37dv3tb38rd72fn58eeOABPfDAA7rvvvvUrVs3HT9+XAEBAXJ3d1dxcbFT/fr16zVo0CD16dNH0h/zkw4cOHBJPTVv3lzvvfeeYz+ltWzZUnv27FGDBg0uabsArixCE4Aaq6CgQBkZGSouLtaRI0eUnJysSZMmKT4+Xg8//HCZ+tdff11hYWG6+eabVatWLX366acKDQ3V9ddfL+mPu+C++eYbtW/fXlarVf7+/mrQoIEWL16shIQEWSwW/fd//7fTc6DMeOihhzRx4kTdc889mjRpksLCwvTTTz8pPDxcsbGx+sc//qH4+HhFRETo/vvvV61atfTLL79o+/btmjBhQmV8VAAqAXfPAaixkpOTFRYWpnr16qlbt25au3at3nrrLX355Zdyc3MrU3/dddfplVdeUevWrXXrrbfqwIED+ve//61atf74p3DKlClatWqVIiIidMstt0j6I2j5+/urXbt2SkhIUNeuXdWyZctL6tPDw0MrV65UcHCwevTooWbNmunll1929Ni1a1ctW7ZMq1at0q233qq2bdtq6tSpioqKusxPCEBlshiGYbi6CQAAgOqOM00AAAAmEJoAAABMIDQBAACYQGgCAAAwgdAEAABgAqEJAADABEITAACACYQmAAAAEwhNAAAAJhCaAAAATCA0AQAAmEBoAgAAMOH/AwKF54rPR2YvAAAAAElFTkSuQmCC",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "from itertools import combinations\n",
    "\n",
    "def euclidean_distance(v1, v2):\n",
    "    return np.linalg.norm(np.array(v1) - np.array(v2))\n",
    "\n",
    "def calculate_distances(vectors):\n",
    "    min_distance = float('inf')\n",
    "    max_distance = 0\n",
    "    distances = []\n",
    "\n",
    "    for pair in combinations(enumerate(vectors), 2):\n",
    "        idx1, vec1 = pair[0]\n",
    "        idx2, vec2 = pair[1]\n",
    "\n",
    "        distance = euclidean_distance(vec1, vec2)\n",
    "        distances.append(distance)\n",
    "\n",
    "        if distance < min_distance:\n",
    "            min_distance = distance\n",
    "            min_pair = (idx1, idx2)\n",
    "\n",
    "        if distance > max_distance:\n",
    "            max_distance = distance\n",
    "            max_pair = (idx1, idx2)\n",
    "\n",
    "    return min_pair, min_distance, max_pair, max_distance, distances\n",
    "\n",
    "def plot_histogram(distances):\n",
    "    plt.hist(distances, bins=np.arange(0, max(distances)+0.1, 0.1), edgecolor='black')\n",
    "    plt.title('Distribution of Euclidean Distances')\n",
    "    plt.xlabel('Distance')\n",
    "    plt.ylabel('Frequency')\n",
    "    plt.show()\n",
    "\n",
    "if __name__ == \"__main__\":\n",
    "    vectors = []\n",
    "    with open('vectors.csv', 'r') as file:\n",
    "        reader = csv.reader(file)\n",
    "        for row in reader:\n",
    "            vectors.append([float(val) for val in row])\n",
    "\n",
    "    min_pair, min_distance, max_pair, max_distance, distances = calculate_distances(vectors)\n",
    "\n",
    "    print(f\"Минимальное расстояние: Вектор {min_pair[0]} и Вектор {min_pair[1]}, Значение: {min_distance}\")\n",
    "    print(f\"Максимальное расстояние: Вектор {max_pair[0]} и Вектор {max_pair[1]}, Значение: {max_distance}\")\n",
    "\n",
    "    plot_histogram(distances)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a9de6497",
   "metadata": {},
   "source": [
    "Осталось перевести получившийся код из ноутбука в программу на Python.\n",
    "А ещё будет интересно попробовать сделать это в Rust."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
